#include "Util.h"

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

double getDiffInNanoSeconds(struct timespec startTime, struct timespec endTime) {
	struct timespec temp;
	double differenceInNanoSeconds; // long long didn't work out for big seconds
	if ((endTime.tv_nsec - startTime.tv_nsec) < 0) {
		temp.tv_sec = endTime.tv_sec - startTime.tv_sec - 1;
		temp.tv_nsec = 1000000000 + endTime.tv_nsec - startTime.tv_nsec;
	} else {
		temp.tv_sec = endTime.tv_sec - startTime.tv_sec;
		temp.tv_nsec = endTime.tv_nsec - startTime.tv_nsec;
	}
	differenceInNanoSeconds = (10e9 * (double) temp.tv_sec)
			+ (double) temp.tv_nsec;
	return differenceInNanoSeconds;
}

void validateAndFillInputArgument(int argc, char* argv[], long *n,
		char *argumentName) {
	if (argc != 2) {
		printf("Usage %s {%s} \n", argv[0], argumentName);
		exit(-1);
	}
	*n = atol(argv[1]);
}

void validateAndFillInputArguments(int argc, char* argv[], long *n1,
		char *argument1Name, long *n2, char *argument2Name) {
	if (argc != 3) {
		printf("Usage %s {%s} {%s} \n", argv[0], argument1Name, argument2Name);
		exit(-1);
	}
	*n1 = atol(argv[1]);
	*n2 = atol(argv[2]);
}

void validateAndFill2InputArgumentsWithOption(int argc, char* argv[], long *n1,
		char *argument1Name, long *n2, char *argument2Name, int *option, char *optionName, int* n3, char* arg3Name) {
	if (argc != 5) {
		printf("Usage %s {%s} {%s} {%s} {%s}\n", argv[0], argument1Name, argument2Name, optionName, arg3Name);
		exit(-1);
	}
	*n1 = atol(argv[1]);
	*n2 = atol(argv[2]);
	*option = atoi(argv[3]);
	*n3 = atoi(argv[4]);
}

long getNextOffsetWithinPage(long offset, long increment, long bufferSize) {
	long pageLowerBoundary = offset / PAGE_SIZE;
	long pageUpperBoundary = (offset / PAGE_SIZE) + PAGE_SIZE;
	long offsetPlusIncrement = offset + increment;
	if (offsetPlusIncrement < pageUpperBoundary
			&& offsetPlusIncrement < bufferSize) {
		return offsetPlusIncrement;
	} else if (offsetPlusIncrement < pageUpperBoundary
			&& !(offsetPlusIncrement < bufferSize)) {
		return (offsetPlusIncrement - bufferSize) + pageLowerBoundary;
	} else {
		return (offsetPlusIncrement - pageUpperBoundary) + pageLowerBoundary;
	}
}

void swapCharacters(char *buffer, long firstOffset, long secondOffset) {
	// Ensure offsets are within the allocated memory :)
	char temp = buffer[firstOffset];
	buffer[firstOffset] = buffer[secondOffset];
	buffer[secondOffset] = temp;
}

void fillAllocatedMemory(char *buffer, long bufferSize) {
	long i = 0;
	for (i = 0; i < bufferSize; i++) {
		buffer[i] = getRandomCharacter();
	}
}

void printStandardMemory() {
	printf("1MB = %lu \n", 1024l * 1024l); //1048576
	printf("512MB = %lu \n ", 1024l * 1024l * 512l); //536870912
	printf("1GB = %lu \n", 1024l * 1024l * 1024l); //1073741824
}

char* getSizeInMB(long bytes) {
	char *str = (char *) malloc(sizeof(char) * 40);
	sprintf(str, "%f MB", (double)bytes / ONE_MB);
	return str;
}

char* getSizeInKB(long bytes) {
	char *str = (char *) malloc(sizeof(char) * 40);
	sprintf(str, "%f KB", (double)bytes / ONE_KB);
	return str;
}

char getRandomCharacter() {
	return (rand() % 26) + 'A';
}
